package customer

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"git.mycaigou.com/gfyx/common/cache"
	"git.mycaigou.com/gfyx/common/usermetadata"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/constants"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/errcode"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/ossfile"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/utils"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/base/user"
	clueRepo "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/clue/clue"
	customerRepo "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/clue/customer"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/clue/report"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/common/file"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/remote/openapi_remote"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/remote/opensearch_remote"
	basePb "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/proto/micro_gfyx_oppty_service_proto/micro-gfyx-oppty-service/base"
	pb "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/proto/micro_gfyx_oppty_service_proto/micro-gfyx-oppty-service/clue"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/service/base/msg"
	"git.myscrm.cn/golang/common/ykerrcode"
	"git.myscrm.cn/golang/stark/v4"
	"strings"
	"time"
)

type customerManageService struct {
	customerRepo       customerRepo.CustomerManageRepositoryIface
	customerImportRepo customerRepo.CustomerImportRepositoryIface
	clueRepo           clueRepo.ClueRepositoryIface
	userOrgRepo        user.UserOrgRepositoryIface
	userRepo           user.UserRepositoryIface
	reportRepo         report.GfyxReportReposIface
	fileRepo           file.FileRepoIface
	openSearchRepos    opensearch_remote.OpenSearchRepositoryIface
	openApiRepo        openapi_remote.OpenApiRepoIface
	msgService         msg.MsgServiceIface
}

func NewCustomerManageService(
	customerRepo customerRepo.CustomerManageRepositoryIface,
	customerImportRepo customerRepo.CustomerImportRepositoryIface,
	clueRepo clueRepo.ClueRepositoryIface,
	userOrgRepo user.UserOrgRepositoryIface,
	userRepo user.UserRepositoryIface,
	reportRepo report.GfyxReportReposIface,
	fileRepo file.FileRepoIface,
	openSearchRepos opensearch_remote.OpenSearchRepositoryIface,
	openApiRepo openapi_remote.OpenApiRepoIface,
	msgService msg.MsgServiceIface,
) CustomerManageServiceIface {
	return &customerManageService{
		customerRepo:       customerRepo,
		customerImportRepo: customerImportRepo,
		clueRepo:           clueRepo,
		userOrgRepo:        userOrgRepo,
		userRepo:           userRepo,
		reportRepo:         reportRepo,
		fileRepo:           fileRepo,
		openSearchRepos:    openSearchRepos,
		openApiRepo:        openApiRepo,
		msgService:         msgService,
	}
}

type UserMsgItem struct {
	UserId   int64
	UserName string
	Total    int32
}

// SaveCustomer 保存客户主表
func (s *customerManageService) SaveCustomer(ctx context.Context, request *pb.SaveCustomerRequest) (*pb.SaveCustomerResponse, error) {
	// todo get db 数据
	// 1, 检验是否存在重复公司
	isExistPo, err := s.customerRepo.GetCustomerByOrganizingCodeOrCompanyName(ctx, request.Id, request.OrganizingCode, request.CompanyName)
	if err != nil {
		return nil, err
	}
	if isExistPo.Id > 0 {
		stark.Logger.Infof(ctx, "method:GetCustomerByOrganizingCodeOrCompanyName,err:%v", err)
		return nil, ykerrcode.TogRPCError(errcode.ClueCustomerRepeatDataError, "信用代码或公司名称重复")
	}
	// 2. 保存客户主表数据
	var customerId int64
	var hasProfile bool
	loginUser := usermetadata.GetMetaUserInfo(ctx)
	detail, _ := s.openApiRepo.GetCompanyDetail(ctx, request.OrganizingCode)
	if detail != nil && detail.OrganizingCode == request.OrganizingCode {
		hasProfile, customerId, err = s.saveCustomerData(ctx, request.Id, request.ResponsibleUserId, loginUser.UserId, request.Group, detail, constants.CustomerSourceList)
		if err != nil {
			return nil, ykerrcode.TogRPCError(errcode.ClueCustomerSaveError, "保存客户主表数据失败")
		}
		if !hasProfile {
			_, err = s.openApiRepo.AddSyncTask(ctx, []string{detail.CompanyName})
			stark.Logger.Infof(ctx, "客户详情主档案不存在，添加到反哺任务，社会信用代码:%s,公司名称:%s,添加反哺任务错误信息:%+v",
				request.OrganizingCode, detail.CompanyName, err)
		}
	} else {
		return nil, ykerrcode.TogRPCError(errcode.CustomerNotExistError, "工商信息不存在，请检查公司信息是否正确")
	}

	// 删除缓存
	cacheRedis, _ := cache.TenantRedis()
	_, err = cacheRedis.Del(ctx, constants.CustomerGroupCacheKey)
	if err != nil {
		// 由于不影响主流程，这里只记录错误，不直接返回
		stark.Logger.Errorf(ctx, "method:DelCache,err:%v", err)
	}

	// 当创建人和负责人不一致时，发送站内信通知
	if loginUser.UserId != request.ResponsibleUserId {
		domain := stark.Configer.(stark.ApolloConfigerIface).GetStringValue("gfyx_front_domain", "https://toker.mycaigou.com")
		siteMsgReq := &basePb.SiteMessageRequest{
			MessageType: basePb.MySiteMessageType_CUSTOMER_ALLOCATION,
			Title:       fmt.Sprintf("尊敬的用户，【%s】已将您添加为【%s】的客户负责人，请及时查看跟进。", loginUser.UserName, request.CompanyName),
			Content:     fmt.Sprintf("尊敬的用户，【%s】已将您添加为【%s】的客户负责人，请及时查看跟进。", loginUser.UserName, request.CompanyName),
			SenderId:    0,
			ReceiverId:  request.ResponsibleUserId,
			Link:        fmt.Sprintf("%s/crm/customer", domain),
			TenantCode:  "",
		}
		_ = s.msgService.PushSiteMsg(ctx, siteMsgReq)
	}

	// 返回数据
	resp := &pb.SaveCustomerResponse{
		Id: customerId,
	}
	return resp, nil
}

// DeleteCustomer 删除用户数据
func (s *customerManageService) DeleteCustomer(ctx context.Context, request *pb.DeleteCustomerRequest) (*pb.DeleteCustomerResponse, error) {
	// 获取用户信息
	loginUser := usermetadata.GetMetaUserInfo(ctx)
	err := s.customerRepo.DeleteCustomer(ctx, loginUser.UserId, request.Id)
	if err != nil {
		stark.Logger.Errorf(ctx, "method:DeleteCustomer,err:%v", err)
		return nil, ykerrcode.TogRPCError(errcode.ClueCustomerDeleteError, "删除客户信息失败")
	}
	return &pb.DeleteCustomerResponse{Rows: 1}, nil
}

func (s *customerManageService) CustomerList(ctx context.Context, request *pb.CustomerListRequest) (*pb.CustomerListResponse, error) {
	// 1. 组装查询条件
	condition := make(map[string]interface{}, 0)
	pageInfo := &utils.PageInfo{Page: int(request.Page), PageSize: int(request.PageSize)}
	// 获取登录用户信息
	loginUser := usermetadata.GetMetaUserInfo(ctx)
	// 组装查询条件-开始
	// 全国还是个人
	if request.Category == "all" {
		// 如果选择个人，则查询个人的客户
		var userIds []int64
		// 获取区域用户
		subUserIds, err := s.userOrgRepo.GetMyResponseOrgUserIds(ctx, loginUser.UserId)
		if err != nil {
			stark.Logger.Errorf(ctx, "GetMyResponsibleAreaUserList error: %v", err)
			return nil, ykerrcode.TogRPCError(errcode.UserOrgResponseOrgUserError, "获取我负责区域联系人失败")
		}
		userIds = append(userIds, subUserIds...)
		subUserIds, err = s.userOrgRepo.GetMyResponseSubOrgUserIds(ctx, loginUser.UserId)
		if err != nil {
			stark.Logger.Errorf(ctx, "GetMyResponseSubOrgUserIds error: %v", err)
			return nil, ykerrcode.TogRPCError(errcode.UserOrgResponseSubOrgUserError, "获取我负责子级区域联系人失败")
		}
		userIds = append(userIds, subUserIds...)
		if len(request.ResponsibleUserIds) > 0 {
			// 如果请求有用户id，那么查询的用户id 只能在有权限的列表里
			var tempIds []int64
			for _, reqId := range request.ResponsibleUserIds {
				for _, id := range userIds {
					if reqId == id {
						tempIds = append(tempIds, id)
					}
				}
			}
			if len(tempIds) == 0 {
				userIds = []int64{}
			} else {
				userIds = tempIds
			}
		}
		userIds = utils.RemoveDuplicatesInt64(userIds)
		condition["responsible_user_ids"] = userIds
	} else {
		condition["c.responsible_user_id"] = loginUser.UserId
	}
	// 公司名称模糊搜索
	if request.Keyword != "" {
		condition["keyword"] = request.Keyword
	}
	// 注册地区
	if len(request.AreaCodes) > 0 {
		condition["area_codes"] = request.AreaCodes
	}
	// 企业分组
	if len(request.Group) > 0 {
		condition["groups"] = request.Group
	}
	// 企业标签
	if len(request.CompanyLabel) > 0 {
		condition["company_label"] = strings.Join(request.CompanyLabel, ",")
	}
	if len(request.CompanyLevel) > 0 {
		condition["company_level"] = strings.Join(request.CompanyLevel, ",")
	}
	if len(request.CompanyIdentity) > 0 {
		condition["company_identity"] = strings.Join(request.CompanyIdentity, ",")
	}
	if len(request.CompanyType) > 0 {
		condition["company_types"] = request.CompanyType
	}
	// 组装查询条件-结束
	// 2. 查询数据
	total, customerList, err := s.customerRepo.QueryCustomerList(ctx, condition, pageInfo)
	if err != nil {
		stark.Logger.Errorf(ctx, "method:MyResponsibleCustomers,err:%v", err)
		return nil, ykerrcode.TogRPCError(errcode.ClueCustomerQueryError, "查询客户列表失败")
	}
	response := &pb.CustomerListResponse{
		Total: total,
		List:  make([]*pb.CustomerListItem, 0),
	}
	// 3, 处理返回数据
	for _, v := range customerList {
		// 处理 logo
		logoUrl := ""
		if v.CompanyLogo != "" && v.YcgCompanyId != "" {
			logoUrl = utils.GetCompanyLogoUrl(v.YcgCompanyId, v.CompanyLogo)
		}
		// 处理标签数据
		companyLabel := make([]*pb.LabelItem, 0)
		if v.CompanyLabel != "" {
			labelNameArr := strings.Split(v.CompanyLabel, ",")
			for _, labelName := range labelNameArr {
				companyLabel = append(companyLabel, &pb.LabelItem{
					Label:  labelName,
					Remark: constants.GetCompanyLabelRemark(labelName),
				})
			}
		}
		companyLevel := make([]*pb.LabelItem, 0)
		if v.CompanyLevel != "" {
			labelNameArr := strings.Split(v.CompanyLevel, ",")
			for _, labelName := range labelNameArr {
				companyLevel = append(companyLevel, &pb.LabelItem{
					Label:  labelName,
					Remark: constants.GetCompanyLabelRemark(labelName),
				})
			}
		}
		companyIdentity := make([]string, 0)
		if v.CompanyIdentity != "" {
			companyIdentity = strings.Split(v.CompanyIdentity, ",")
		}
		// 如果顶级公司是本身自己，则不显示顶级公司
		if v.TopCompanyName == v.CompanyName {
			v.TopCompanyName = ""
			v.TopCompanyOrganizingCode = ""
		}
		response.List = append(response.List, &pb.CustomerListItem{
			Id:                       v.Id,
			CompanyName:              v.CompanyName,
			OrganizingCode:           v.OrganizingCode,
			CompanyLogo:              logoUrl,
			Group:                    v.Group,
			BusinessStatus:           v.BusinessStatus,
			TopCompanyName:           v.TopCompanyName,
			TopCompanyOrganizingCode: v.TopCompanyOrganizingCode,
			CompanyIdentity:          companyIdentity,
			CompanyType:              v.CompanyType,
			CompanyLevel:             companyLevel,
			CompanyLabel:             companyLabel,
			Province:                 v.Province,
			City:                     v.City,
			ProvinceCode:             v.ProvinceCode,
			CityCode:                 v.CityCode,
			ClueCnt:                  v.ClueCnt,
			ReportCnt:                v.ReportCnt,
			BidCnt_2Year:             v.BidCnt2Year,
			TakeLandCnt_2Year:        v.TakeLandCnt2Year,
			CommencePermitCnt_2Year:  v.CommencePermitCnt2Year,
			SellProjectCnt_2Year:     v.SellProjectCnt2Year,
			CooperationCaseCnt_2Year: v.CooperationCaseCnt2Year,
			CreditLevel:              v.CreditLevel,
			ResponsibleUserName:      v.ResponsibleUserName,
			ResponsibleUserId:        v.ResponsibleUserID,
			CreatedBy:                v.CreatedBy,
			CreatedByUserName:        v.CreatedByUserName,
			CreatedOn:                v.CreatedOn.Format("2006-01-02 15:04:05"),
		})
	}

	return response, nil
}

func (s *customerManageService) CustomerGroupOption(ctx context.Context, request *pb.CustomerGroupOptionRequest) (*pb.CustomerGroupOptionResponse, error) {
	// 优先从缓存获取
	cacheRedis, _ := cache.TenantRedis()
	cacheList, _ := cacheRedis.Get(ctx, constants.CustomerGroupCacheKey)
	if cacheList != "" {
		group := strings.Split(cacheList, ",")
		return &pb.CustomerGroupOptionResponse{
			List: group,
		}, nil
	} else {
		group, err := s.customerRepo.GetCustomerGroup(ctx)
		if err != nil {
			stark.Logger.Errorf(ctx, "method:CustomerGroupOption,err:%v", err)
			return nil, ykerrcode.TogRPCError(errcode.ClueCustomerGroupOptionError, "获取客户分组数据失败")
		}
		// 设置缓存
		if len(group) > 0 {
			_, _ = cacheRedis.Set(ctx, constants.CustomerGroupCacheKey, strings.Join(group, ","), true, 7200)
		}

		return &pb.CustomerGroupOptionResponse{
			List: group,
		}, nil
	}
}

func (s *customerManageService) ImportFile(ctx context.Context, request *pb.ImportCustomerRequest) (*pb.ImportCustomerResponse, string, error) {
	// 1.检查当前用户是否有进行中的导入任务
	status, err := s.getImportMissionStatus(ctx)
	if status == constants.ImportMissionStatusRunning {
		return nil, "", ykerrcode.TogRPCError(errcode.ImportIsRunningTask, "已有导入任务正在进行中，请等待导入完成")
	}

	// 2.获取文件下载地址, 并下载文件
	if request.FileId == 0 {
		return nil, "", ykerrcode.TogRPCError(errcode.ImportFileIdIsNull, "文件id不能为空")
	}
	fileInfo, err := s.fileRepo.QueryById(ctx, request.FileId)
	if err != nil {
		return nil, "", ykerrcode.TogRPCError(errcode.ImportFileIsNotExist, "文件不存在")
	}

	// 组装oss的下载地址
	fileUrl, err := ossfile.GetSignURL(fileInfo.FilePath)
	if err != nil {
		stark.Logger.Errorf(ctx, "method:ImportFile,err:%v", err)
		return nil, "", ykerrcode.TogRPCError(errcode.ImportFileGetDownloadUrlError, "获取下载文件的 url 失败")
	}

	// 2. 读取文件内容, 校验文件内容
	rowData, err := utils.ReadRemoteExcelData(fileUrl)
	if err != nil {
		stark.Logger.Infof(ctx, "客户导入文件格式错误：文件下载地址：%s，错误信息：%s", fileUrl, err.Error())
		return nil, "", ykerrcode.TogRPCError(errcode.ImportFileFormatError, "导入的文件格式错误")
	}

	if len(rowData) <= 2 {
		return nil, "", ykerrcode.TogRPCError(errcode.ImportFileIsEmpty, "导入文件内容为空")
	} else if len(rowData) > 1002 {
		return nil, "", ykerrcode.TogRPCError(errcode.ImportFileDataExceedsLimit, "导入记录超过1000条,请分批导入")
	}

	if len(rowData[1]) < 3 || rowData[1][0] != "客户名称" || rowData[1][1] != "客户负责人" || rowData[1][2] != "客户分组" {
		return nil, "", ykerrcode.TogRPCError(errcode.ImportFileFormatError, "导入模板文件错误")
	}

	// 将数据筛入缓存
	loginUser := usermetadata.GetMetaUserInfo(ctx)
	cacheRedis, _ := cache.TenantRedis()
	cacheKey := fmt.Sprintf("%s%d", constants.ImportCustomerDataTemp, loginUser.UserId)
	marshal, err := json.Marshal(rowData)
	if err != nil {
		return nil, "", err
	}
	_, _ = cacheRedis.Set(ctx, cacheKey, string(marshal), true, 7200)

	return &pb.ImportCustomerResponse{Total: int32(len(rowData))}, cacheKey, nil
}

func (s *customerManageService) ImportFileByJob(ctx context.Context, fileId, userId int64, rowData [][]string) error {
	// 1. 加锁
	err := s.lockImportFile(ctx)
	if err != nil {
		return err
	}
	// 释放锁
	defer func() {
		_ = s.unlockImportFile(ctx)
	}()

	if len(rowData) <= 2 {
		return ykerrcode.TogRPCError(errcode.ImportFileIsEmpty, "导入文件内容为空")
	} else if len(rowData) > 1001 {
		return ykerrcode.TogRPCError(errcode.ImportFileDataExceedsLimit, "导入记录超过1000条,请分批导入")
	}

	// 2. 导入数据
	var customerNameList, userList, groupList, syncTask []string
	importCustomerRecordList := make([]*customerRepo.CustomerImportPo, 0)
	messageList := make(map[int64]int64)
	for i := 2; i < len(rowData); i++ {
		if len(rowData[i]) > 0 {
			customerNameList = append(customerNameList, rowData[i][0])
		}
		if len(rowData[i]) > 1 {
			userList = append(userList, rowData[i][1])
		}
		if len(rowData[i]) > 2 {
			groupList = append(groupList, rowData[i][2])
		}
	}
	// 预先加载客户名称
	_, customerPoList, err := s.customerRepo.QueryCustomerList(ctx, map[string]interface{}{"company_name_list": customerNameList}, nil)
	if err != nil {
		stark.Logger.Errorf(ctx, "method:ImportFileByJob,err:%v", err)
		return err
	}
	existCustomerMap := make(map[string]bool)
	for _, i := range customerPoList {
		existCustomerMap[i.CompanyName] = true
	}
	// 预先加载用户名称
	_, userPoList, err := s.userRepo.QueryUserList(ctx, map[string]interface{}{"user_names": userList, "status": constants.UserStatusNormal, "is_deleted": constants.IsDeletedFalse}, nil, "")
	if err != nil {
		stark.Logger.Errorf(ctx, "method:ImportFileByJob,err:%v", err)
		return err
	}
	existUserMap := make(map[string]int64)
	for _, i := range userPoList {
		existUserMap[i.Name] = i.Id
	}

	// 从第二行循环读取文件, 开始循环
	for i := 2; i < len(rowData); i++ {
		// 2.1  如果三个数据任意不存在, 则跳过处理
		var companyName, responsibleUserName, customerGroup string
		if len(rowData[i]) > 0 {
			companyName = strings.TrimSpace(rowData[i][0])
		}
		if len(rowData[i]) > 1 {
			responsibleUserName = strings.TrimSpace(rowData[i][1])
		}
		if len(rowData[i]) > 2 {
			customerGroup = strings.TrimSpace(rowData[i][2])
		}
		recordPo := &customerRepo.CustomerImportPo{
			FileId:              fileId,
			CompanyName:         companyName,
			ResponsibleUserName: responsibleUserName,
			ResponsibleUserId:   0,
			CustomerGroup:       customerGroup,
			CreatedBy:           userId,
			CreatedOn:           time.Now(),
			ModifiedBy:          userId,
			ModifiedOn:          time.Now(),
			IsDeleted:           constants.IsDeletedFalse,
		}
		if companyName == "" && responsibleUserName == "" && customerGroup == "" {
			continue
		}
		// 无效数据，直接跳过
		if companyName == "" {
			recordPo.Status = constants.CustomerImportStatusFailed
			recordPo.Remark = "客户名称不能为空"
			importCustomerRecordList = append(importCustomerRecordList, recordPo)
			continue
		}
		if responsibleUserName == "" {
			recordPo.Status = constants.CustomerImportStatusFailed
			recordPo.Remark = "负责人名称不能为空"
			importCustomerRecordList = append(importCustomerRecordList, recordPo)
			continue
		}
		if customerGroup == "" {
			recordPo.Status = constants.CustomerImportStatusFailed
			recordPo.Remark = "客户分组不能为空"
			importCustomerRecordList = append(importCustomerRecordList, recordPo)
			continue
		}

		// 2.2 负责人不存在，跳过
		if _, ok := existUserMap[responsibleUserName]; !ok {
			recordPo.Status = constants.CustomerImportStatusFailed
			recordPo.Remark = responsibleUserName + "不存在，请重新选择负责人"
			importCustomerRecordList = append(importCustomerRecordList, recordPo)
			continue
		} else {
			recordPo.ResponsibleUserId = existUserMap[responsibleUserName]
		}

		// 2.3 如果客户已经存在在我的客户里面，则跳过
		if _, ok := existCustomerMap[companyName]; ok {
			recordPo.Status = constants.CustomerImportStatusFailed
			recordPo.Remark = companyName + ", 公司已经存在，请勿重复导入"
			importCustomerRecordList = append(importCustomerRecordList, recordPo)
			continue
		}
		// 2.4 调用工商信息接口，判断是否合法
		detail, _ := s.openApiRepo.GetCompanyDetail(ctx, companyName)
		if detail != nil && detail.CompanyName == companyName {
			isExistProfile, _, err := s.saveCustomerData(ctx, 0, existUserMap[responsibleUserName], userId, customerGroup, detail, constants.CustomerSourceImport)
			if err != nil {
				stark.Logger.Errorf(ctx, "method:ImportFileByJob,err:%v", err)
				continue
			}
			// 如果不存在，则进行反哺
			if !isExistProfile {
				syncTask = append(syncTask, companyName)
			}
			// 放入数组重新判断
			existCustomerMap[companyName] = true
			recordPo.Status = constants.CustomerImportStatusSucceed
			recordPo.Remark = ""
			importCustomerRecordList = append(importCustomerRecordList, recordPo)
			// 添加到站内信列表
			if _, ok := messageList[existUserMap[responsibleUserName]]; !ok {
				messageList[existUserMap[responsibleUserName]] = 1
			} else {
				messageList[existUserMap[responsibleUserName]] = messageList[existUserMap[responsibleUserName]] + 1
			}
		} else {
			recordPo.Status = constants.CustomerImportStatusFailed
			recordPo.Remark = "工商信息校验不通过，请重新更改客户名称"
			importCustomerRecordList = append(importCustomerRecordList, recordPo)
		}
	}

	// 2.7 批量插入导入记录
	if len(importCustomerRecordList) > 0 {
		err = s.customerImportRepo.BatchSave(ctx, importCustomerRecordList)
		if err != nil {
			return ykerrcode.TogRPCError(errcode.ImportFileEditError, "保存客户记录失败")
		}
	}

	// 3. 反哺
	if len(syncTask) > 0 {
		_, err = s.openApiRepo.AddSyncTask(ctx, syncTask)
	}

	// 4. 清除缓存
	cacheRedis, _ := cache.TenantRedis()
	_, _ = cacheRedis.Del(ctx, constants.CustomerGroupCacheKey)

	// 5. 发送站内信（给我添加其他的人发送）
	userPo, _ := s.userRepo.GetUserByCondition(ctx, map[string]interface{}{"id": userId})
	for receiverUserId, total := range messageList {
		domain := stark.Configer.(stark.ApolloConfigerIface).GetStringValue("gfyx_front_domain", "https://toker.mycaigou.com")
		siteMsgReq := &basePb.SiteMessageRequest{
			MessageType: basePb.MySiteMessageType_CUSTOMER_ALLOCATION,
			Title:       fmt.Sprintf("尊敬的用户，【%s】为您分配了【%d】家客户，请及时查看跟进。", userPo.Name, total),
			Content:     fmt.Sprintf("尊敬的用户，【%s】为您分配了【%d】家客户，请及时查看跟进。", userPo.Name, total),
			SenderId:    0,
			ReceiverId:  receiverUserId,
			Link:        fmt.Sprintf("%s/crm/customer", domain),
			TenantCode:  "",
		}
		_ = s.msgService.PushSiteMsg(ctx, siteMsgReq)
	}

	return nil
}

// ImportCustomerList 获取导入列表
func (s *customerManageService) ImportCustomerList(ctx context.Context, request *pb.ImportCustomerListRequest) (*pb.ImportCustomerListResponse, error) {
	condition := map[string]interface{}{}
	if request.Status != 0 {
		condition["status"] = request.Status
	}
	if request.Keyword != "" {
		condition["keyword"] = request.Keyword
	}
	if request.StartTime != "" {
		condition["start_time"] = request.StartTime
	}
	if request.EndTime != "" {
		condition["end_time"] = request.EndTime
	}

	// 默认 第1页，20条
	pageInfo := &utils.PageInfo{
		Page:     1,
		PageSize: 20,
	}
	if request.Page > 0 && request.PageSize > 0 {
		pageInfo.Page = int(request.Page)
		pageInfo.PageSize = int(request.PageSize)
	}

	total, importList, err := s.customerImportRepo.Query(ctx, condition, pageInfo)
	if err != nil {
		stark.Logger.Errorf(ctx, "method:ImportCustomerList,err:%v", err)
		return nil, ykerrcode.TogRPCError(errcode.ImportFileGetListError, "获取客户导入列表失败")
	}
	response := &pb.ImportCustomerListResponse{
		Total: total,
		List:  make([]*pb.ImportCustomerItem, 0),
	}

	for _, v := range importList {
		response.List = append(response.List, &pb.ImportCustomerItem{
			Id:                  v.Id,
			FileId:              v.FileId,
			Status:              v.Status,
			CompanyName:         v.CompanyName,
			ResponsibleUserName: v.ResponsibleUserName,
			ResponsibleUserId:   v.ResponsibleUserId,
			CustomerGroup:       v.CustomerGroup,
			Remark:              v.Remark,
			CreatedBy:           v.CreatedBy,
			CreatedOn:           v.CreatedOn.Format("2006-01-02 15:04:05"),
		})
	}
	return response, nil
}

func (s *customerManageService) ImportCustomerStatus(ctx context.Context, request *pb.ImportCustomerStatusRequest) (*pb.ImportCustomerStatusResponse, error) {
	// 1. 查看缓存中是否有导入任务
	response := &pb.ImportCustomerStatusResponse{}
	status, err := s.getImportMissionStatus(ctx)
	if status == constants.ImportMissionStatusRunning {
		response.Status = status
		return response, nil
	}
	// 2. 从数据库中获取导入任务状态
	loginUser := usermetadata.GetMetaUserInfo(ctx)
	_, importList, err := s.customerImportRepo.Query(ctx, map[string]interface{}{"created_by": loginUser.UserId, "is_deleted": constants.IsDeletedFalse}, &utils.PageInfo{Page: 1, PageSize: 1})
	if err != nil {
		return nil, err
	}

	if len(importList) == 0 {
		response.Status = constants.ImportMissionStatusNotExists
		return response, nil
	}

	response.Status = constants.ImportMissionStatusFinished
	response.FileId = importList[0].FileId
	response.ImportTime = importList[0].CreatedOn.Format("2006-01-02 15:04:05")

	response.SucceedCount, err = s.customerImportRepo.Count(ctx,
		map[string]interface{}{"file_id": response.FileId,
			"is_deleted": constants.IsDeletedFalse,
			"status":     constants.CustomerPoolImportStatusSucceed})
	response.FailedCount, err = s.customerImportRepo.Count(ctx,
		map[string]interface{}{"file_id": response.FileId,
			"is_deleted": constants.IsDeletedFalse,
			"status":     constants.CustomerPoolImportStatusFailed})
	if err != nil {
		return nil, err
	}
	return response, nil
}

func (s *customerManageService) ImportCustomerEdit(ctx context.Context, request *pb.ImportCustomerEditRequest) error {
	if request == nil || request.Id == 0 || request.CompanyName == "" {
		return nil
	}
	_, importList, err := s.customerImportRepo.Query(ctx, map[string]interface{}{"id": request.Id, "is_deleted": constants.IsDeletedFalse}, nil)
	if err != nil {
		return err
	}
	if len(importList) == 0 {
		return ykerrcode.TogRPCError(errcode.ImportFileEditError, "编辑记录不存在")
	}
	existImportRecord := importList[0]
	if existImportRecord.Status == constants.CustomerPoolImportStatusSucceed {
		return ykerrcode.TogRPCError(errcode.ImportFileEditError, "导入成功的记录，不能编辑")
	}
	// 查找联系人是否存在
	userPo, err := s.userRepo.GetUserByCondition(ctx, map[string]interface{}{"id": request.ResponsibleUserId, "is_deleted": constants.IsDeletedFalse, "status": constants.UserStatusNormal})
	if err != nil {
		return ykerrcode.TogRPCError(errcode.ImportFileEditError, "导入的负责人不存在")
	}

	// 获取工商信息，opensearch 补充远程数据
	loginUser := usermetadata.GetMetaUserInfo(ctx)
	detail, _ := s.openApiRepo.GetCompanyDetail(ctx, request.CompanyName)
	if detail != nil && detail.CompanyName == request.CompanyName {
		// 如果存在的话，不能再继续添加
		isExistPo, err := s.customerRepo.GetCustomerByOrganizingCodeOrCompanyName(ctx, request.Id, detail.OrganizingCode, request.CompanyName)
		if err != nil {
			return err
		}
		if isExistPo.Id > 0 {
			stark.Logger.Infof(ctx, "method:GetCustomerByOrganizingCodeOrCompanyName,err:%v", err)
			return ykerrcode.TogRPCError(errcode.ClueCustomerRepeatDataError, "信用代码或公司名称重复")
		}
		isExistProfile, _, err := s.saveCustomerData(ctx, 0, request.ResponsibleUserId, loginUser.UserId, existImportRecord.CustomerGroup, detail, constants.CustomerSourceImport)
		if err != nil {
			return ykerrcode.TogRPCError(errcode.ImportFileEditError, "保存客户失败")
		}
		// 如果不存在，则进行反哺
		if !isExistProfile {
			_, _ = s.openApiRepo.AddSyncTask(ctx, []string{detail.CompanyName})
		}
	} else {
		return ykerrcode.TogRPCError(errcode.ImportFileEditError, "企业的工商信息不存在，请重新输入")
	}
	// 更新记录
	updates := map[string]interface{}{
		"company_name":          request.CompanyName,
		"responsible_user_name": userPo.Name,
		"responsible_user_id":   userPo.Id,
		"status":                constants.CustomerPoolImportStatusSucceed,
		"modified_by":           loginUser.UserId,
		"modified_on":           time.Now(),
	}
	err = s.customerImportRepo.Update(ctx, map[string]interface{}{"id": existImportRecord.Id}, updates)
	if err != nil {
		return ykerrcode.TogRPCError(errcode.ImportFileEditError, "更新导入记录失败，请重试")
	}
	// 发送短信
	if loginUser.UserId != request.ResponsibleUserId {
		domain := stark.Configer.(stark.ApolloConfigerIface).GetStringValue("gfyx_front_domain", "https://toker.mycaigou.com")
		siteMsgReq := &basePb.SiteMessageRequest{
			MessageType: basePb.MySiteMessageType_CUSTOMER_ALLOCATION,
			Title:       fmt.Sprintf("尊敬的用户，【%s】已将您添加为【%s】的客户负责人，请及时查看跟进。", loginUser.UserName, request.CompanyName),
			Content:     fmt.Sprintf("尊敬的用户，【%s】已将您添加为【%s】的客户负责人，请及时查看跟进。", loginUser.UserName, request.CompanyName),
			SenderId:    0,
			ReceiverId:  request.ResponsibleUserId,
			Link:        fmt.Sprintf("%s/crm/customer", domain),
			TenantCode:  "",
		}
		_ = s.msgService.PushSiteMsg(ctx, siteMsgReq)
	}
	return nil
}

func (s *customerManageService) ImportCustomerDelete(ctx context.Context, request *pb.ImportCustomerDeleteRequest) error {
	condition := map[string]interface{}{"ids": request.Id}
	loginUser := usermetadata.GetMetaUserInfo(ctx)
	return s.customerImportRepo.Delete(ctx, condition, loginUser.UserId)
}

func (s *customerManageService) ImportCustomerCount(ctx context.Context, request *pb.ImportCustomerCountRequest) (*pb.ImportCustomerCountResponse, error) {
	succeedCount, err := s.customerImportRepo.Count(ctx, map[string]interface{}{
		"is_deleted": constants.IsDeletedFalse,
		"status":     constants.CustomerPoolImportStatusSucceed,
	})
	if err != nil {
		return nil, err
	}
	failedCount, err := s.customerImportRepo.Count(ctx, map[string]interface{}{
		"is_deleted": constants.IsDeletedFalse,
		"status":     constants.CustomerPoolImportStatusFailed,
	})
	if err != nil {
		return nil, err
	}

	return &pb.ImportCustomerCountResponse{
		TotalCount:   succeedCount + failedCount,
		SucceedCount: succeedCount,
		FailedCount:  failedCount,
	}, nil
}

func (s *customerManageService) saveCustomerData(ctx context.Context, id, responsibleUserId, userId int64, customerGroup string, detail *openapi_remote.CompanyDetailBo, source int32) (bool, int64, error) {
	// 初始化数据
	var hasProfile bool
	var err error
	customerPo := &customerRepo.CustomerPo{}
	if id > 0 {
		customerPo, err = s.customerRepo.GetCustomerInfo(ctx, map[string]interface{}{"id": id})
		if err != nil {
			return false, 0, err
		}
	} else {
		customerPo.CreatedBy = userId
		customerPo.CreatedOn = time.Now()
	}
	customerIndexPo := &customerRepo.CustomerIndexPo{}
	customerTagPo := &customerRepo.CustomerTagPo{}
	// 客户主档案赋值
	customerPo.CompanyName = detail.CompanyName
	customerPo.OrganizingCode = detail.OrganizingCode
	customerPo.ResponsibleUserID = responsibleUserId
	customerPo.Province = detail.Province
	customerPo.ProvinceCode = detail.ProvinceCode
	customerPo.City = detail.City
	customerPo.CityCode = detail.CityCode
	if customerGroup == "" {
		customerPo.Group = constants.CustomerGroupDefaultName
	} else {
		customerPo.Group = customerGroup
	}

	customerPo.Source = source
	customerPo.ModifiedBy = userId
	customerPo.ModifiedOn = time.Now()
	customerPo.IsDeleted = constants.IsDeletedFalse
	// 2.5 调用 opensearch 接口补数据，如果不存在则加入反哺队列
	detailList, _ := s.openSearchRepos.GetCustomerDetail(ctx, &opensearch_remote.GetCustomerDetailRequest{OrganizingCodes: detail.OrganizingCode})
	if detailList != nil && len(detailList) > 0 {
		customerPo.TopCompanyName = detailList[0].TopCompanyName
		customerPo.TopOrganizingCode = detailList[0].TopCompanyOrganizingCode
		customerPo.CompanyLogo = detailList[0].DeveloperLogo
		customerPo.BusinessStatus = detailList[0].BusinessStatusLabel
		customerPo.CompanyType = detailList[0].CompanyType
		customerPo.CreditLevel = detailList[0].CreditLevelLabel
		customerPo.HasProfile = 1
		customerPo.YcgCompanyId = detailList[0].DeveloperId

		// 指标赋值
		customerIndexPo.BidCount2Year = detailList[0].BidCnt2Year
		customerIndexPo.TakeLandCount2Year = detailList[0].TakeLandCnt2Year
		customerIndexPo.CommencePermitCount2Year = detailList[0].CommencePermitCnt2Year
		customerIndexPo.SellProjectCount2Year = detailList[0].SellProjectCnt2Year
		customerIndexPo.CooperationCaseCount2Year = detailList[0].CooperationCaseCnt2Year

		// 标签赋值
		customerTagPo.CompanyLabel = s.transCompanyLabel(detailList[0].CompanyLabelArr)
		customerTagPo.CompanyLevel = s.transCompanyLevel(detailList[0].CompanyLevelArr)
		customerTagPo.CompanyIdentity = s.transCompanyIdentity(detailList[0].IsSupplier, detailList[0].IsDeveloper)
	} else {
		// 加入反哺数据
		hasProfile = false
	}
	// 2.6 保存客户数据
	customerPo, err = s.customerRepo.SaveCustomer(ctx, customerPo)
	if err != nil {
		stark.Logger.Errorf(ctx, "method:SaveCustomer,err:%v", err)
		return hasProfile, 0, errors.New("保存客户主数据失败")
	}
	// 保存客户指标
	customerIndexPo.CustomerId = customerPo.Id
	customerIndexPo.ClueCnt, _ = s.clueRepo.ClueCount(ctx, map[string]interface{}{"a.company_name": customerPo.CompanyName, "a.is_deleted": 0})
	customerIndexPo.ReportCnt, _ = s.reportRepo.ReportCount(ctx, map[string]interface{}{"a.company_name": customerPo.CompanyName, "a.is_deleted": 0})
	err = s.customerRepo.SaveCustomerIndex(ctx, customerIndexPo)
	if err != nil {
		stark.Logger.Errorf(ctx, "method:SaveCustomerIndex,err:%v", err)
		return hasProfile, customerPo.Id, errors.New("保存客户指标失败")
	}
	// 保存客户标签
	customerTagPo.CustomerId = customerPo.Id
	customerTagPo.CreatedBy = userId
	customerTagPo.CreatedOn = time.Now()
	customerTagPo.ModifiedBy = userId
	customerTagPo.ModifiedOn = time.Now()
	err = s.customerRepo.SaveCustomerTags(ctx, customerTagPo)
	if err != nil {
		stark.Logger.Errorf(ctx, "method:import-SaveCustomerTags,err:%v", err)
		return hasProfile, customerPo.Id, errors.New("保存客户标签失败")
	}
	return hasProfile, customerPo.Id, nil
}

func (s *customerManageService) transCompanyLabel(companyLabelArr []opensearch_remote.CustomerLabel) string {
	// company_label->企业标签, 拼接成 , 格式
	companyLabel := ""
	if len(companyLabelArr) > 0 {
		for _, v := range companyLabelArr {
			companyLabel += v.Name + ","
		}
		companyLabel = strings.TrimRight(companyLabel, ",")
	}
	return companyLabel
}

func (s *customerManageService) transCompanyLevel(companyLevelArr []opensearch_remote.CustomerLabel) string {
	// company_level->企业等级
	companyLevel := ""
	if len(companyLevelArr) > 0 {
		for _, v := range companyLevelArr {
			companyLevel += v.Name + ","
		}
		companyLevel = strings.TrimRight(companyLevel, ",")
	}
	return companyLevel
}

func (s *customerManageService) transCompanyIdentity(isSupplier, isDeveloper int32) string {
	// company_identity->企业属性
	companyIdentity := ""
	if isSupplier == 1 {
		companyIdentity += "上下游单位,"
	}
	if isDeveloper == 1 {
		companyIdentity += "甲方单位,"
	}
	if len(companyIdentity) > 0 {
		companyIdentity = strings.TrimRight(companyIdentity, ",")
	}
	return companyIdentity
}

func (s *customerManageService) lockImportFile(ctx context.Context) error {
	cacheRedis, _ := cache.TenantRedis()
	num, err := cacheRedis.Incr(ctx, constants.ImportCustomerScene)
	if err != nil {
		return err
	}
	if num > 1 {
		return errors.New("已有导入任务正在进行中，请等待导入完成")
	}
	//缓存半小时，半小时导入仍未完成，自动释放锁
	_, err = cacheRedis.Expire(ctx, constants.ImportCustomerScene, 30*60)
	if err != nil {
		return err
	}
	return nil
}

func (s *customerManageService) unlockImportFile(ctx context.Context) error {
	cacheRedis, _ := cache.TenantRedis()
	_, err := cacheRedis.Del(ctx, constants.ImportCustomerScene)
	if err != nil {
		stark.Logger.Errorf(ctx, "客户导入锁释放失败")
	}
	return nil
}

func (s *customerManageService) getImportMissionStatus(ctx context.Context) (int32, error) {
	cacheRedis, _ := cache.TenantRedis()
	num, err := cacheRedis.Get(ctx, constants.ImportCustomerScene)
	if err != nil {
		return 0, err
	}
	// key存在，则说明导入还在进行中,不存在说明当前没有导入正在执行
	if num != "" {
		return constants.ImportMissionStatusRunning, nil
	} else {
		return constants.ImportMissionStatusNotExists, nil
	}
}

func (s *customerManageService) QueryExportCustomerBatchData(ctx context.Context, condition interface{}, batchNum, batchSize int32) (rowTitle []string, rowData [][]string, err error) {
	rowTitle = strings.Split(constants.JobTypeCustomerExportFields, "，")
	var request *pb.CustomerListRequest
	switch condition.(type) {
	case *pb.CustomerListRequest:
		request = condition.(*pb.CustomerListRequest)
	case string:
		request = &pb.CustomerListRequest{}
		if condition.(string) != "" {
			err = json.Unmarshal([]byte(condition.(string)), request)
			if err != nil {
				stark.Logger.Errorf(ctx, "客户管理-获取导出记录条数错误,condition:%+v, err:%s", condition, err)
				return
			}
		}
	}
	request.Page, request.PageSize = batchNum, batchSize
	listData, err := s.CustomerList(ctx, request)
	if err != nil {
		return nil, nil, err
	}
	if listData == nil || len(listData.List) == 0 {
		return
	}

	for _, item := range listData.List {
		companyLevelStr := ""
		for _, v := range item.CompanyLevel {
			companyLevelStr += v.Label + ","
		}
		companyLabelStr := ""
		for _, v := range item.CompanyLabel {
			companyLabelStr += v.Label + ","
		}
		rowData = append(rowData, []string{
			item.CompanyName,                                 //公司名称，
			item.OrganizingCode,                              //社会统一信用代码，
			item.Group,                                       //分组，
			item.BusinessStatus,                              //经营状态，
			strings.Join(item.CompanyIdentity, ","),          //企业性质，
			item.CompanyType,                                 //企业类型，
			strings.TrimRight(companyLevelStr, ","),          //企业等级，
			strings.TrimRight(companyLabelStr, ","),          //企业标签，
			item.ResponsibleUserName,                         //负责人，
			fmt.Sprintf("%d", item.ClueCnt),                  //客户线索，
			fmt.Sprintf("%d", item.ReportCnt),                //客户报备，
			item.CreatedByUserName,                           //创建人
			item.CreatedOn,                                   //创建时间，
			fmt.Sprintf("%d", item.BidCnt_2Year),             //近两年招标，
			fmt.Sprintf("%d", item.TakeLandCnt_2Year),        //近两年拿地，
			fmt.Sprintf("%d", item.CommencePermitCnt_2Year),  //近两年开工，
			fmt.Sprintf("%d", item.SellProjectCnt_2Year),     //近两年开盘，
			fmt.Sprintf("%d", item.CooperationCaseCnt_2Year), //近两年合作
		})
	}
	return
}

// UpdateCustomerByCron 更新数据
func (s *customerManageService) UpdateCustomerByCron(ctx context.Context) (string, error) {
	// 1. 查找需要更新的客户
	result := ""
	total, customerList, err := s.customerRepo.QuerySimpleCustomerList(ctx, map[string]interface{}{"is_deleted": constants.IsDeletedFalse}, nil)
	if err != nil {
		stark.Logger.Errorf(ctx, "method:QuerySimpleCustomerList,err:%v", err)
		return result, err
	}

	successCnt := 0
	failedCnt := 0
	// 2. 调用 opensearch 补充数据
	for _, customer := range customerList {
		detail := &openapi_remote.CompanyDetailBo{
			CompanyName:    customer.CompanyName,
			OrganizingCode: customer.OrganizingCode,
			CityCode:       customer.CityCode,
			City:           customer.City,
			ProvinceCode:   customer.ProvinceCode,
			Province:       customer.Province,
		}
		_, _, err := s.saveCustomerData(ctx, customer.Id, customer.ResponsibleUserID, customer.CreatedBy, customer.Group, detail, customer.Source)
		if err != nil {
			stark.Logger.Errorf(ctx, "method:saveCustomerData,company_name: %s, err:%v", customer.CompanyName, err)
			failedCnt++
			continue
		} else {
			successCnt++
		}
	}
	result = fmt.Sprintf("共%d条数据需要更新, 成功:%d, 失败:%d", total, successCnt, failedCnt)
	return result, nil
}
